package com.frank.loadinglibrary.common.element;

import com.frank.loadinglibrary.base.baseanimations.BaseAnimationController;
import com.frank.loadinglibrary.base.baseelement.BaseElement;
import com.frank.loadinglibrary.base.baseelement.IComponentCallback;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;

import java.util.ArrayList;

/**
 * @author eric_shaw
 * @version 1.0
 * @description 菊花加载效果Element
 * @classname BallBeatElement.class
 * @program loadinglibrary
 * @date 2021/06/07
 **/
public class BallBeatElement extends BaseElement implements BaseAnimationController.IAnimationController<AnimatorValue> {

    private final int valueTwo = 2;
    /**
     * 设置允许的最大个数
     */
    private static final int DEFAULT_COUNT = 3;
    /**
     * 延时基数
     */
    private static final int BASE_DELAY_TIME = 120;
    /**
     * 左右边距
     */
    private static final float DEFAULT_MAGIN_HOR = 10;
    public static final float SCALE = 1.0f;
    public static final float ALPHA = 1.0f;


    /**
     * 设置延时动画的时间基准
     */
    private int delayTime = BASE_DELAY_TIME;

    /**
     * 画笔
     */
    private Paint mPaint;

    /**
     *组件回调接口
     */
    private IComponentCallback callback;
    /**
     * 可配置参数
     */
    private BallBeatParams params;

    private BallBeatElement(BallBeatParams ballBeatParams, IComponentCallback call) {

        this.params = ballBeatParams;
        this.callback = call;
    }

    @Override
    public void draw(Canvas canvas) {
        if (params.radius <= 0) {
            //如果没有给定半径，则以宽度250 边距10 间距10  进行计算 半径
            params.radius = (getWidth() - (getWidth() / 250.f) * params.spacingHor * (getBallCount() - 1) - DEFAULT_MAGIN_HOR * 2) / (getBallCount() * 2);
        } else {
            //给定半径 根据半径 以25个像素半径间距10为基准线计算间距
            params.spacingHor = params.radius * 10 / 25;
        }
        float x = 0;
        float y = 0;
        //根据球的个数计算第一个球的起始位置
        if (getBallCount() % valueTwo == 0) {
            x = getWidth() / 2 - (getBallCount() * params.radius - (getBallCount() / 2 - 1) * params.spacingHor - params.spacingHor / 2);
            y = getHeight() / 2;
        } else {
            x = getWidth() / 2 - (getBallCount() * params.radius - getBallCount() / 2 * params.spacingHor);
            y = getHeight() / 2;
        }
        for (int i = 0; i < getBallCount(); i++) {
            canvas.save();
            Color currentColor = Color.WHITE;
            if (params.colorPalette != null && params.colorPalette.length > 0) {
                currentColor = new Color(Color.getIntColor(params.colorPalette[i % params.colorPalette.length]));
            }
            mPaint.setColor(currentColor);
            float translateX = x + (params.radius * 2) * i + params.spacingHor * i;
            canvas.translate(translateX, y);
            canvas.scale(params.scaleFloats[i], params.scaleFloats[i]);
            mPaint.setAlpha(params.alphaFloats[i]);
            canvas.drawCircle(0, 0, params.radius, mPaint);
            canvas.rotate(60);
            canvas.restore();
        }
    }

    @Override
    public BaseAnimationController.IAnimationController initAnimationController() {
        return this;
    }

    @Override
    public void initPaint() {
        if (mPaint == null) {
            mPaint = new Paint();
            mPaint.setColor(Color.WHITE);
            mPaint.setStyle(Paint.Style.FILL_STYLE);
            mPaint.setAntiAlias(true);
        }
    }

    @Override
    public ArrayList<AnimatorValue> onCreateAnimators() {
        ArrayList<AnimatorValue> animators = new ArrayList<>();
        if (BASE_DELAY_TIME * getBallCount() > params.durtion) {
            //设置时长的3/4 为基准线去计算延时时间
            delayTime = params.durtion * 3 / 4 / getBallCount();
        }
        for (int i = 0; i < getBallCount(); i++) {
            final int index = i;
            AnimatorValue scaleAnim = new AnimatorValue();
            scaleAnim.setDuration(params.durtion);
            scaleAnim.setLoopedCount(-1);
            scaleAnim.setDelay(delayTime * (i + 1));
            scaleAnim.setValueUpdateListener((animatorValue, v) -> {
                //设定 0.3 - 1之间缩放
                if (v < 0.5f) {
                    params.scaleFloats[index] = (float) (-1.4 * v + 1);
                } else {
                    params.scaleFloats[index] = (float) (1.4 * v - 0.4);
                }
                if (callback != null) {
                    callback.reflushComponent();
                }
            });

            if (params.enableAlphaAnimator) {
                AnimatorValue alphaAnim = new AnimatorValue();
                alphaAnim.setDuration(params.durtion);
                alphaAnim.setLoopedCount(-1);
                alphaAnim.setDelay(delayTime * (i + 1));
                alphaAnim.setValueUpdateListener((animatorValue, v) -> {
                    if (v < 0.5f) {
                        params.alphaFloats[index] = (-408 * v + 255) / 255;
                    } else {
                        params.alphaFloats[index] = (408 * v - 153) / 255;
                    }
                    if (callback != null) {
                        callback.reflushComponent();
                    }
                });
                animators.add(alphaAnim);

            }
            animators.add(scaleAnim);
        }
        return animators;
    }

    @Override
    public void onAnimationReset() {
        //do nothing because donot need to reset animation params
    }

    /**
     * @return int
     * @Description 获取绘制个数
     **/
    private int getBallCount() {
        return params.ballCount;
    }

    /**
     * 构建者
     */
    public static class BallBeatBuild {

        BallBeatParams params;
        IComponentCallback call;

        public BallBeatBuild(IComponentCallback c) {
            call = c;
            params = new BallBeatParams();
            setBallCount(DEFAULT_COUNT);
            setDurtion(BallBeatParams.BASE_DURTION_TIME);
        }

        BallBeatBuild setBallCount(int count) {
            params.ballCount = count;
            params.scaleFloats = new float[params.ballCount];
            params.alphaFloats = new float[params.ballCount];
            for (int i = 0; i < params.ballCount; i++) {
                params.scaleFloats[i] = SCALE;
                params.alphaFloats[i] = ALPHA;
            }
            return this;
        }

        BallBeatBuild setSpacingHor(float space) {
            params.spacingHor = space;
            return this;
        }

        BallBeatBuild setColorPalette(String[] colors) {
            params.colorPalette = colors;
            return this;
        }

        BallBeatBuild setEnableAlphaAnimator(boolean alphaEnble) {
            params.enableAlphaAnimator = alphaEnble;
            return this;
        }


        BallBeatBuild setEnableRotationAnimator(boolean rorateEnble) {
            params.enableRotationAnimator = rorateEnble;
            return this;
        }

        BallBeatBuild setRadius(float radiu) {
            params.radius = radiu;
            return this;
        }

        public BallBeatBuild setDurtion(int dur) {
            params.durtion = dur;
            return this;
        }

        public BallBeatElement build() {
            return new BallBeatElement(params, call);
        }
    }

    /***
     * 可配置参数类
     */
    public static class BallBeatParams {
        //默认时长基数
        private static final int BASE_DURTION_TIME = 1000;
        //配置旋转动画开关
        public boolean enableRotationAnimator = false;
        //配置球个数
        private int ballCount = 10;
        //配置颜色数组
        protected String[] colorPalette;
        //配置透明度动画
        private boolean enableAlphaAnimator = false;
        //配置半径
        private float radius = 0;
        //配置水平间隔
        private float spacingHor = 10;
        //缩放数组
        public float[] scaleFloats;
        //透明度数组
        public float[] alphaFloats;
        //设置动画时间基数
        private int durtion = BASE_DURTION_TIME;

    }
}
